﻿using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace WorldOnFire
{
    public static class SInputManager
    {
        // Why not
        private const int GAMEPAD_COUNT = 4;

        // Player index for quick
        private static int m_nPlayerIndex = 0;

        // Current and previous state for buffered input
        private static GamePadState[] m_GamePadStates = new GamePadState[GAMEPAD_COUNT];
        private static GamePadState[] m_PreviousGamePadStates = new GamePadState[GAMEPAD_COUNT];
        private static KeyboardState m_KeyboardState = new KeyboardState();
        private static KeyboardState m_PreviousKeyboardState = new KeyboardState();

        /// <summary>
        /// Gets the GamePadState for each controller and stores the previous one.
        /// </summary>
        public static void Update()
        {
            for (int iGamePad = 0; iGamePad < GAMEPAD_COUNT; ++iGamePad)
            {
                m_PreviousGamePadStates[iGamePad] = m_GamePadStates[iGamePad];
                m_GamePadStates[iGamePad] = GamePad.GetState((PlayerIndex)iGamePad, GamePadDeadZone.Circular);
            }

            m_PreviousKeyboardState = m_KeyboardState;
            m_KeyboardState = Keyboard.GetState();
        }

        /// <summary>
        /// Returns the player's index.
        /// </summary>
        /// <returns>The player index.</returns>
        public static int GetPlayerIndex()
        {
            return m_nPlayerIndex;
        }

        /// <summary>
        /// Sets the player index. Should only be called when entering a lobby.
        /// </summary>
        /// <param name="_nPlayerIndex">The player index.</param>
        public static void SetPlayerIndex(int _nPlayerIndex)
        {
            m_nPlayerIndex = _nPlayerIndex;
        }

        /// <summary>
        /// Returns whether or not the specified button is currently down.
        /// </summary>
        /// <param name="_eButton">The button to test.</param>
        /// <param name="_nGamePadIndex">The GamePad index.</param>
        /// <returns>Whether or not the button is down.</returns>
        public static bool IsButtonDown(Buttons _eButton, int _nGamePadIndex)
        {
            return m_GamePadStates[_nGamePadIndex].IsButtonDown(_eButton);
        }

        /// <summary>
        /// Returns whether or not the specified button is currently down, using the player index to decide which GamePad to query.
        /// </summary>
        /// <param name="_eButton">The button to test.</param>
        /// <returns>Whether or not the button is down.</returns>
        public static bool IsButtonDown(Buttons _eButton)
        {
            return m_GamePadStates[m_nPlayerIndex].IsButtonDown(_eButton);
        }

        /// <summary>
        /// Returns whether or not the specified button is currently up.
        /// </summary>
        /// <param name="_eButton">The button to test.</param>
        /// <param name="_nGamePadIndex">The GamePad index.</param>
        /// <returns>Whether or not the button is up.</returns>
        public static bool IsButtonUp(Buttons _eButton, int _nGamePadIndex)
        {
            return m_GamePadStates[_nGamePadIndex].IsButtonUp(_eButton);
        }

        /// <summary>
        /// Returns whether or not the specified button is currently up, using the player index to decide which GamePad to query.
        /// </summary>
        /// <param name="_eButton">The button to test.</param>
        /// <returns>Whether or not the button is up.</returns>
        public static bool IsButtonUp(Buttons _eButton)
        {
            return m_GamePadStates[m_nPlayerIndex].IsButtonUp(_eButton);
        }

        /// <summary>
        /// Returns whether or not the specified button was pressed between the last frame and current frame.
        /// </summary>
        /// <param name="_eButton">The button to test.</param>
        /// <param name="_nGamePadIndex">The GamePad index.</param>
        /// <returns>Whether or not the button was pressed.</returns>
        public static bool IsButtonPressed(Buttons _eButton, int _nGamePadIndex)
        {
            return (m_GamePadStates[_nGamePadIndex].IsButtonDown(_eButton) &&
                m_PreviousGamePadStates[_nGamePadIndex].IsButtonUp(_eButton));
        }

        /// <summary>
        /// Returns whether or not the specified button was pressed between the last frame and current frame, using the player index to decide which GamePad to query.
        /// </summary>
        /// <param name="_eButton">The button to test.</param>
        /// <returns>Whether or not the button was pressed.</returns>
        public static bool IsButtonPressed(Buttons _eButton)
        {
            return (m_GamePadStates[m_nPlayerIndex].IsButtonDown(_eButton) &&
                m_PreviousGamePadStates[m_nPlayerIndex].IsButtonUp(_eButton));
        }

        /// <summary>
        /// Returns whether or not the specified button was released between the last frame and current frame.
        /// </summary>
        /// <param name="_eButton">The button to test.</param>
        /// <param name="_nGamePadIndex">The GamePad index.</param>
        /// <returns>Whether or not the button was released.</returns>
        public static bool IsButtonReleased(Buttons _eButton, int _nGamePadIndex)
        {
            return (m_GamePadStates[_nGamePadIndex].IsButtonUp(_eButton) &&
                m_PreviousGamePadStates[_nGamePadIndex].IsButtonDown(_eButton));
        }

        /// <summary>
        /// Returns whether or not the specified button was released between the last frame and current frame, using the player index to decide which GamePad to query.
        /// </summary>
        /// <param name="_eButton">The button to test.</param>
        /// <returns>Whether or not the button was released.</returns>
        public static bool IsButtonReleased(Buttons _eButton)
        {
            return (m_GamePadStates[m_nPlayerIndex].IsButtonUp(_eButton) &&
                m_PreviousGamePadStates[m_nPlayerIndex].IsButtonDown(_eButton));
        }

        /// <summary>
        /// Returns the position of the left thumbstick.
        /// </summary>
        /// <param name="_nGamePadIndex">The GamePad index.</param>
        /// <returns>The position of the left thumbstick (0.0 - 1.0)</returns>
        public static Vector2 GetLeftThumbStick(int _nGamePadIndex)
        {
            return m_GamePadStates[_nGamePadIndex].ThumbSticks.Left;
        }

        /// <summary>
        /// Returns the position of the left thumbstick, using the player index to decide which GamePad to query.
        /// </summary>
        /// <returns>The position of the left thumbstick (0.0 - 1.0)</returns>
        public static Vector2 GetLeftThumbStick()
        {
            return m_GamePadStates[m_nPlayerIndex].ThumbSticks.Left;
        }

        /// <summary>
        /// Returns the position of the right thumbstick.
        /// </summary>
        /// <param name="_nGamePadIndex">The GamePad index.</param>
        /// <returns>The position of the right thumbstick (0.0 - 1.0)</returns>
        public static Vector2 GetRightThumbStick(int _nGamePadIndex)
        {
            return m_GamePadStates[_nGamePadIndex].ThumbSticks.Right;
        }

        /// <summary>
        /// Returns the position of the right thumbstick, using the player index to decide which GamePad to query.
        /// </summary>
        /// <returns>The position of the right thumbstick (0.0 - 1.0)</returns>
        public static Vector2 GetRightThumbStick()
        {
            return m_GamePadStates[m_nPlayerIndex].ThumbSticks.Right;
        }

        /// <summary>
        /// Returns the position of the left trigger.
        /// </summary>
        /// <param name="_nGamePadIndex">The GamePad index.</param>
        /// <returns>The position of the left trigger (0.0 - 1.0)</returns>
        public static float GetLeftTrigger(int _nGamePadIndex)
        {
            return m_GamePadStates[_nGamePadIndex].Triggers.Left;
        }

        /// <summary>
        /// Returns the position of the left trigger, using the player index to decide which GamePad to query.
        /// </summary>
        /// <param name="_nGamePadIndex">The GamePad index.</param>
        /// <returns>The position of the left trigger (0.0 - 1.0)</returns>
        public static float GetLeftTrigger()
        {
            return m_GamePadStates[m_nPlayerIndex].Triggers.Left;
        }

        /// <summary>
        /// Returns the position of the right trigger.
        /// </summary>
        /// <param name="_nGamePadIndex">The GamePad index.</param>
        /// <returns>The position of the right trigger (0.0 - 1.0)</returns>
        public static float GetRightTrigger(int _nGamePadIndex)
        {
            return m_GamePadStates[_nGamePadIndex].Triggers.Right;
        }

        /// <summary>
        /// Returns the position of the right trigger, using the player index to decide which GamePad to query.
        /// </summary>
        /// <param name="_nGamePadIndex">The GamePad index.</param>
        /// <returns>The position of the right trigger (0.0 - 1.0)</returns>
        public static float GetRightTrigger()
        {
            return m_GamePadStates[m_nPlayerIndex].Triggers.Right;
        }

        // TODO: Document
        public static bool IsKeyDown(Keys _Key)
        {
            return m_KeyboardState.IsKeyDown(_Key);
        }

        public static bool IsKeyUp(Keys _Key)
        {
            return m_KeyboardState.IsKeyUp(_Key);
        }

        public static bool IsKeyPressed(Keys _Key)
        {
            return m_KeyboardState.IsKeyDown(_Key) && m_PreviousKeyboardState.IsKeyUp(_Key);
        }

        public static bool IsKeyReleased(Keys _Key)
        {
            return m_KeyboardState.IsKeyUp(_Key) && m_PreviousKeyboardState.IsKeyDown(_Key);
        }
    }
}
